import type {
  Decimal,
  Numeric,
  Expression,
  XExpression,
  Star,
  Scalar,
  Time,
  Uuid,
  DbType,
  ScalarFromDbType,
  Condition,
  Field,
  Sort,
} from './sql';

export interface VirtualOperation {
  identityValue(
    table: XExpression<string>,
    column: XExpression<string>
  ): Expression<number | bigint>;

  count(expr: Star<any> | XExpression<Scalar>): Expression<number>;

  avg<T extends Numeric>(expr: XExpression<T>): Expression<T>;

  sum<T extends Numeric>(expr: XExpression<T>): Expression<T>;

  max<
    T extends
      | string
      | number
      | bigint
      | boolean
      | Decimal
      | Date
      | Time
      | Uuid
      | null
  >(
    expr: Expression<T>
  ): Expression<T>;

  min<
    T extends
      | string
      | number
      | bigint
      | boolean
      | Decimal
      | Date
      | Time
      | Uuid
      | null
  >(
    expr: Expression<T>
  ): Expression<T>;

  rownum(orderBy: Sort[], partitionBy?: Field): Expression<number>;

  convert<T extends DbType>(
    expr: XExpression<Scalar>,
    toType: T
  ): Expression<ScalarFromDbType<T>>;

  now(): Expression<Date>;

  utcNow(): Expression<Date>;

  switchTimezone(
    date: XExpression<Date>,
    offset: XExpression<string>
  ): Expression<Date>;

  formatDate(date: XExpression<Date>, format: string): Expression<string>;

  yearOf(date: XExpression<Date>): Expression<number>;

  monthOf(date: XExpression<Date>): Expression<number>;

  dayOf(date: XExpression<Date>): Expression<number>;

  daysBetween(
    start: XExpression<Date>,
    end: XExpression<Date>
  ): Expression<number>;

  monthsBetween(
    start: XExpression<Date>,
    end: XExpression<Date>
  ): Expression<number>;

  yearsBetween(
    start: XExpression<Date>,
    end: XExpression<Date>
  ): Expression<number>;

  hoursBetween(
    start: XExpression<Date>,
    end: XExpression<Date>
  ): Expression<number>;

  minutesBetween(
    start: XExpression<Date>,
    end: XExpression<Date>
  ): Expression<number>;

  secondsBetween(
    start: XExpression<Date>,
    end: XExpression<Date>
  ): Expression<number>;

  addDays(
    date: XExpression<Date>,
    days: XExpression<Numeric>
  ): Expression<Date>;

  addMonths(
    date: XExpression<Date>,
    months: XExpression<Numeric>
  ): Expression<Date>;

  addYears(
    date: XExpression<Date>,
    years: XExpression<Numeric>
  ): Expression<Date>;

  addHours(
    date: XExpression<Date>,
    hours: XExpression<Numeric>
  ): Expression<Date>;

  addMinutes(
    date: XExpression<Date>,
    minutes: XExpression<Numeric>
  ): Expression<Date>;

  addSeconds(
    date: XExpression<Date>,
    seconds: XExpression<Numeric>
  ): Expression<Date>;

  strlen(str: XExpression<string>): Expression<number>;

  substr(
    str: XExpression<string>,
    start: XExpression<Numeric>,
    length: XExpression<Numeric>
  ): Expression<string>;

  replace(
    str: XExpression<string>,
    search: XExpression<string>,
    to: XExpression<string>
  ): Expression<string>;

  trim(str: XExpression<string>): Expression<string>;

  trimEnd(str: XExpression<string>): Expression<string>;

  upper(str: XExpression<string>): Expression<string>;

  lower(str: XExpression<string>): Expression<string>;

  strpos(
    str: XExpression<string>,
    search: XExpression<string>,
    startAt?: XExpression<number>
  ): Expression<number>;

  // ascii(str: XExpression<string>): Expression<number>;

  // asciiChar(code: XExpression<number>): Expression<string>;

  // unicode(str: XExpression<string>): Expression<number>;

  // unicodeChar(code: XExpression<number>): Expression<string>;

  nvl<T extends Scalar>(
    value: XExpression<T>,
    defaultValue: XExpression<T>
  ): Expression<T>;

  abs<T extends Numeric>(value: XExpression<T>): Expression<T>;

  exp<T extends Numeric>(value: XExpression<T>): Expression<T>;

  ceil<T extends Numeric>(value: XExpression<T>): Expression<T>;

  floor<T extends Numeric>(value: XExpression<T>): Expression<T>;

  ln<T extends Numeric>(value: XExpression<T>): Expression<T>;

  log<T extends Numeric>(value: XExpression<T>): Expression<T>;

  pi(): Expression<number>;

  power<T extends Numeric>(
    a: XExpression<T>,
    b: XExpression<Numeric>
  ): Expression<T>;

  radians<T extends Numeric>(value: XExpression<T>): Expression<T>;

  degrees<T extends Numeric>(value: XExpression<T>): Expression<T>;

  random(): Expression<number>;

  round<T extends Numeric>(
    value: XExpression<T>,
    s?: XExpression<Numeric>
  ): Expression<T>;

  sign<T extends Numeric>(value: XExpression<T>): Expression<T>;

  sqrt(value: XExpression<Numeric>): Expression<number>;

  cos(value: XExpression<Numeric>): Expression<number>;

  sin(value: XExpression<Numeric>): Expression<number>;

  tan(value: XExpression<Numeric>): Expression<number>;

  acos(value: XExpression<Numeric>): Expression<number>;

  asin(value: XExpression<Numeric>): Expression<number>;

  atan(value: XExpression<Numeric>): Expression<number>;

  atan2(value: XExpression<Numeric>): Expression<number>;

  cot(value: XExpression<Numeric>): Expression<number>;

  existsTable(table: XExpression<string>): Condition;

  existsDatabase(database: string): Condition;

  existsView(name: XExpression<string>): Condition;

  existsFunction(name: XExpression<string>): Condition;

  existsProcedure(name: XExpression<string>): Condition;

  existsSequence(name: XExpression<string>): Condition;

  currentDatabase(): Expression<string>;

  defaultSchema(): Expression<string>;

  nextValue(
    sequenceName: XExpression<string>
  ): Expression<Numeric>;
}
